package personnal.blogprinter;

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;

import org.apache.log4j.Logger;

import personnal.blogprinter.data.PostError;
import personnal.blogprinter.data.PostRange;
import personnal.blogprinter.data.Settings;
import personnal.blogprinter.exceptions.ExtractionException;
import personnal.blogprinter.exceptions.NetworkException;

public class ThreadedBlogPrinter extends BlogPrinter implements WorkDoneListener {

	private static final int DEFAULT_THREAD_COUNT = 10;

	private static Logger logger = Logger.getLogger(ThreadedBlogPrinter.class);
	
	private int threadCount = DEFAULT_THREAD_COUNT;
	protected CountDownLatch countDownLatch;

	public ThreadedBlogPrinter(Settings settings) throws ExtractionException {
		super(settings);
	}
	
	public void setThreadCount(int threadCount) {
		this.threadCount = threadCount;
	}

	public void extract() throws NetworkException, ExtractionException {
		countDownLatch = new CountDownLatch(threadCount);

		Queue<PostRange> inputQueue = new ConcurrentLinkedQueue<PostRange>();
		fillInQueue(inputQueue);
		Queue<PostError> errorQueue = new ConcurrentLinkedQueue<PostError>();
		logger.info("Creating and starting threads (count="+threadCount+")");
		for (int i = 0; i < threadCount; i++) {
			logger.info("Creating Worker-"+i);
			Thread thread = new Thread(createWorker(inputQueue, errorQueue), "Worker-"+i);
			logger.info("Starting Worker-"+i);
			thread.start();
		}
		try {
			logger.info("Waiting for threads completion");
			countDownLatch.await();
		} catch (InterruptedException e) {
			throw new ExtractionException("Application has been interrupted", e);
		}
		handlePostErrors(errorQueue);
	}

	protected BlogWorker createWorker(Queue<PostRange> inputQueue, Queue<PostError> errorQueue) throws NetworkException {
		BlogWorker worker = new BlogWorker(settings, inputQueue, errorQueue);
		worker.setWorkDoneListener(this);
		return worker;
	}

	public void workDone() {
		logger.info("Thread \""+Thread.currentThread().getName()+"\" has finished its work");
		countDownLatch.countDown();
	}
}
